package com.vcc.boss.controller;


import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckSafe;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.write.metadata.WriteSheet;
import com.mybatisflex.core.paginate.Page;
import com.vcc.channel.base.model.request.CardRechargeDto;
import com.vcc.channel.base.service.ChannelBaseService;
import com.vcc.core.annotations.RestPack;
import com.vcc.core.derive.admin.DeriveRegulation;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.*;
import com.vcc.data.entity.*;
import com.vcc.service.boss.request.regulation.AccountRegulationDto;
import com.vcc.service.boss.response.regulation.RegulationVoBoss;
import com.vcc.service.sa.BossUserUtil;
import com.vcc.service.service.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Log4j2
@RestController
@RequestMapping("regulation")
public class RegulationController {


    @Autowired
    private UserService userService;
    @Autowired
    private WalletDetailService walletDetailService;
    @Autowired
    private WalletService walletService;
    @Autowired
    private RegulationService regulationService;
    @Autowired
    private UserCardService userCardService;
    @Autowired
    private CurrencyService currencyService;
    @Autowired
    private BossUserService bossUserService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private CardOrderService cardOrderService;

    @RestPack
    @PostMapping("accountRegulation")
    @SaCheckPermission(value = "wallet:regulation:account:create")
    @SaCheckLogin
    @SaCheckSafe("ACCOUNT_REGULATION")
    public void accountRegulation(
            @RequestBody @Validated AccountRegulationDto accountRegulationDto
    ) {
        if (Objects.equals(accountRegulationDto.getAmount().compareTo(BigDecimal.valueOf(0)), 0)) {
            throw new ProgramException("金额不能等于0");
        }
        //account  账户调账  card  卡调账
        if (accountRegulationDto.getType().equals("account")) {
            User user = userService.getById(accountRegulationDto.getUserId());
            if (!BossUserUtil.hasAllData() && user.getBeLongToDealer().equals(BossUserUtil.getId())) {
                throw new ProgramException("无权操作该用户的账户调账");
            }
            Wallet userWallet = walletService.getByUserIdAndCurrencyCode(user.getId(), accountRegulationDto.getCurrencyCode());
            String orderId = StringUtils.isNotBlank(accountRegulationDto.getOrderId()) ? accountRegulationDto.getOrderId() : IdWorker.getStringOrderId();
            BigDecimal userWalletAmount;
            BigDecimal amount = accountRegulationDto.getAmount();
            if (accountRegulationDto.getAmountType().equals("subtract")) {
                //用户转出
                userWalletAmount = walletService.subtractUsableQuotaById(userWallet.getId(), amount, 2, true);
            } else {
                //用户充值
                userWalletAmount = walletService.addUsableQuotaById(userWallet.getId(), amount, 1, false);
            }
            //0,手续费返还'
            //1,手续费补扣'
            //2,罚金'
            //3,返点发放'
            //4,卡退款退还'
            //5,强制清算扣款'
            String remark = RegexUtil.checkStringIsNull(accountRegulationDto.getRemark()) ? "" : accountRegulationDto.getRemark();
            switch (accountRegulationDto.getUseFlag()) {
                case 0 -> {
                    remark = "手续费返还，" + remark;
                }
                case 1 -> {
                    remark = "手续费补扣，" + remark;
                }
                case 2 -> {
                    remark = "罚金，" + remark;
                }
                case 3 -> {
                    remark = "返点发放，" + remark;
                }
                case 4 -> {
                    remark = "卡退款退还，" + remark;
                }
                case 5 -> {
                    remark = "强制清算扣款，" + remark;
                }
                default -> throw new ProgramException("调账事件错误");
            }
            walletDetailService.accountRegulation(
                    orderId,
                    remark,
                    amount,
                    userWalletAmount,
                    userWallet.getCurrencyId(),
                    userWallet.getUserId(),
                    accountRegulationDto.getAmountType().equals("add")
            );
            Regulation regulation = new Regulation();
            regulation.setUserId(accountRegulationDto.getUserId());
            regulation.setType("account");
            regulation.setAmount(accountRegulationDto.getAmount());
            regulation.setUseFlag(accountRegulationDto.getUseFlag());
            regulation.setCurrencyCode(accountRegulationDto.getCurrencyCode());
            regulation.setAmountType(accountRegulationDto.getAmountType());
            regulation.setOperationUserId(BossUserUtil.getId());
            regulation.setOrderId(orderId);
            regulation.setRemark(remark);
            regulation.setRequestDate(new Date());
            regulationService.save(regulation);
        } else if (accountRegulationDto.getType().equals("card")) {
            UserCard userCard = userCardService.getById(accountRegulationDto.getCardId());
            Long dealerId = userService.getDealerIdById(userCard.getUserId());
            if (!BossUserUtil.hasAllData() && !dealerId.equals(BossUserUtil.getId())) {
                throw new ProgramException("无权操作该用户的卡调账");
            }
            String orderId = IdWorker.getStringOrderId();
            BigDecimal amount = accountRegulationDto.getAmount();
            String remark = RegexUtil.checkStringIsNull(accountRegulationDto.getRemark()) ? "" : accountRegulationDto.getRemark();
            remark = "强制平账，" + remark;
            ChannelBaseService channelBaseService = applicationContext.getBean(userCard.getChannelCode(), ChannelBaseService.class);
            if (accountRegulationDto.getAmountType().equals("subtract")) {
                throw new ProgramException("卡调账功能维护中，暂不可用");
                //卡转出
//                cardOrderService.withdrawCard(
//                        orderId,
//                        userCard.getCardTypeId(),
//                        userCard.getUserId(),
//                        BossUserUtil.getId(),
//                        userCard.getCardNumber(),
//                        userCard.getId(),
//                        userCard.getChannelCode(),
//                        amount,
//                        userCard.getCurrencyCode(),
//                        remark,
//                        "SYSTEM"
//                );
//                channelBaseService.withdraw(
//                        CardWithdrawDto.builder()
//                                .channelCardId(userCard.getChannelCardId())
//                                .withdrawAmount(amount)
//                                .requestId(orderId)
//                                .cardNumberId(userCard.getId())
//                                .cardNumber(userCard.getCardNumber())
//                                .build()
//                );
            } else {
                //卡充值
                cardOrderService.rechargeCard(
                        orderId,
                        userCard.getCardTypeId(),
                        userCard.getUserId(),
                        BossUserUtil.getId(),
                        userCard.getCardNumber(),
                        userCard.getId(),
                        userCard.getChannelCode(),
                        amount,
                        userCard.getCurrencyCode(),
                        remark,
                        "SYSTEM"
                );
                walletService.systemCardRecharge(
                        userCard.getUserId(),
                        BossUserUtil.getId(),
                        userCard.getCurrencyCode(),
                        orderId,
                        userCard.getCardTypeId(),
                        userCard.getCardNumber(),
                        userCard.getId(),
                        userCard.getChannelCode(),
                        amount,
                        remark,
                        "SYSTEM"
                );
                channelBaseService.recharge(
                        CardRechargeDto.builder()
                                .channelCardId(userCard.getChannelCardId())
                                .rechargeAmount(amount)
                                .requestId(orderId)
                                .cardNumberId(userCard.getId())
                                .cardNumber(userCard.getCardNumber())
                                .build()
                );

            }

            Regulation regulation = new Regulation();
            regulation.setCardId(accountRegulationDto.getCardId());
            regulation.setType("card");
            regulation.setAmount(accountRegulationDto.getAmount());
            regulation.setUseFlag(accountRegulationDto.getUseFlag());
            regulation.setCurrencyCode(accountRegulationDto.getCurrencyCode());
            regulation.setOperationUserId(BossUserUtil.getId());
            regulation.setAmountType(accountRegulationDto.getAmountType());
            regulation.setOrderId(orderId);
            regulation.setRemark(remark);
            regulation.setRequestDate(new Date());
            regulationService.save(regulation);
        } else {
            throw new ProgramException("渠道错误，无法操作");
        }
    }


    @RestPack
    @GetMapping("paging")
    @SaCheckLogin
    @SaCheckPermission(value = "wallet:regulation:list:view")
    public Page<RegulationVoBoss> paging(Page<Regulation> pageable, String type, Integer useFlag, Long targetUserId, String startDate, String endDate, Long dealerId) {
        Page<Regulation> paging = regulationService.paging(pageable, type, targetUserId, useFlag, startDate, endDate, dealerId);
        if (paging.getRecords().isEmpty()) {
            return Page.of(
                    paging.getPageNumber(),
                    paging.getPageSize()
            );
        }
        return paging.map(RegulationVoBoss::new);
    }

    @GetMapping("derive")
    @SaCheckPermission(value = "wallet:regulation:list:derive")
    @SaCheckLogin
    public void derive(
            String type,
            Integer useFlag,
            Long targetUserId,
            String startDate,
            String endDate,
            Long dealerId,
            HttpServletResponse response
    ) {
        if (RegexUtil.checkStringIsNull(startDate)) {
            throw new ProgramException("请选择开始时间");
        }
        if (RegexUtil.checkStringIsNull(endDate)) {
            throw new ProgramException("请选择结束时间");
        }
        Long pages = 1L;
        Page<Regulation> paging;
        String fileName = System.currentTimeMillis() + "调账订单.xlsx";
        ExcelWriter excelWriter;
        try {
            ExportUtil.setExcelResponseHeaders(response, fileName);
            excelWriter = ExportUtil.createExcelWriter(response.getOutputStream(), DeriveRegulation.class);
        } catch (Exception e) {
            log.error("导出调账订单数据失败", e);
            throw new ProgramException("导出调账订单数据失败");
        }
        WriteSheet writeSheet = ExportUtil.createWriteSheet("调账订单", DeriveRegulation.class);
        do {
            paging = regulationService.paging(
                    Page.of(pages++, 500),
                    type,
                    targetUserId,
                    useFlag,
                    startDate,
                    endDate,
                    dealerId
            );
            List<DeriveRegulation> list = paging.getRecords().stream().map(it -> DeriveRegulation.builder()
                    .id(it.getId())
                    .type(it.getType().equals("card") ? "卡调账" : "账户调账")
                    .useFlag(it.getUseFlag())
                    .orderId(it.getOrderId())
                    .amountType(it.getUseFlag())
                    .amount(it.getAmount())
                    .currencyCode(it.getCurrencyCode())
                    .cardNumber(it.getCardNumber())
                    .remark(it.getRemark())
                    .requestDate(it.getRequestDate())
                    .account(it.getAccount())
                    .operationAccount(it.getOperationAccount())
                    .dealerAccount(it.getDealerAccount())
                    .build()).collect(Collectors.toList());
            ExportUtil.writeData(excelWriter, writeSheet, list);
            list = null;
        } while (!(pages).equals(paging.getTotalPage() + 1));
        ExportUtil.closeExcelWriter(excelWriter);
    }
}
